//
//  PSTrickTests.m
//  PrefCore
//
//  Created by Sergey on 2/10/14.
//  Copyright (c) 2014 Play-on-smart. All rights reserved.
//

#import <XCTest/XCTest.h>
#import "PSTrick.h"

@interface PSTrickTests : XCTestCase

@end

@implementation PSTrickTests

// PSTrickSize

-(void)testTrickSize {
    PSTrickHash trick = 0;
    XCTAssertEqual(PSTrickSize(trick), 0);
    trick = PSTrickAddCardTalon(trick, [PSCard cardWithSuit:kSuitClubs andRank:kRankSeven].compressed);
    XCTAssertEqual(PSTrickSize(trick), 0);
    trick = PSTrickAddCardPlayer(trick, 0, [PSCard cardWithSuit:kSuitClubs andRank:kRankEight].compressed);
    XCTAssertEqual(PSTrickSize(trick), 1);
    trick = PSTrickAddCardPlayer(trick, 1, [PSCard cardWithSuit:kSuitClubs andRank:kRankNine].compressed);
    XCTAssertEqual(PSTrickSize(trick), 2);
    trick = PSTrickAddCardPlayer(trick, 2, [PSCard cardWithSuit:kSuitClubs andRank:kRankAce].compressed);
    XCTAssertEqual(PSTrickSize(trick), 3);
}

// PSTrickAddCardTalon

-(void)testTrickAddCardTalon {
    for (int i = 0 ; i != PS_CARD_RANK_COUNT ; i++) {
        PSCardRank rank = PSCardRankRising[i];
        for (int j = 0 ; j != PS_CARD_SUIT_RISING_LEN ; j++) {
            PSCardSuit suit = PSCardSuitRising[j];
            PSCard *talonCard = [PSCard cardWithSuit:suit andRank:rank];
            PSTrickHash trick = PSTrickAddCardTalon(0, talonCard.compressed);
            PSCard *talonBack = PSTrickTalonCard(trick);
            XCTAssertNotNil(talonBack);
            XCTAssertEqualObjects(talonCard, talonBack);
        }
    }
}

// PSTrickAddCardPlayer

-(void)testTrickAddSingleCardPlayer {
    for (int p = 0 ; p != 3 ; p++) {
        PSPlayer *player = [[PSPlayer alloc] initWithId:p];
        for (int i = 0 ; i != PS_CARD_RANK_COUNT ; i++) {
            PSCardRank rank = PSCardRankRising[i];
            for (int j = 0 ; j != PS_CARD_SUIT_RISING_LEN ; j++) {
                PSCardSuit suit = PSCardSuitRising[j];
                PSCard *card = [PSCard cardWithSuit:suit andRank:rank];
                PSTrickHash trick = 0;
                trick = PSTrickAddCardPlayer(trick, p, card.compressed);
                PSCard *cardBack = PSTrickCardOfPlayer(trick, player);
                XCTAssertNotNil(cardBack);
                XCTAssertEqualObjects(card, cardBack);
            }
        }
    }
}

-(void)testTrickAddMultipleCards {
    PSPlayer *one = [[PSPlayer alloc] initWithId:0];
    PSPlayer *two = [[PSPlayer alloc] initWithId:1];
    PSPlayer *three = [[PSPlayer alloc] initWithId:2];
    PSTrickHash trick = 0;
    PSCard *c1 = [PSCard cardWithSuit:kSuitClubs andRank:kRankQueen];
    PSCard *c2 = [PSCard cardWithSuit:kSuitClubs andRank:kRankKing];
    PSCard *c3 = [PSCard cardWithSuit:kSuitClubs andRank:kRankAce];
    trick = PSTrickAddCardPlayer(trick, 0, c1.compressed);
    XCTAssertEqualObjects(c1, PSTrickCardOfPlayer(trick, one));
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    XCTAssertEqualObjects(c1, PSTrickCardOfPlayer(trick, one));
    XCTAssertEqualObjects(c2, PSTrickCardOfPlayer(trick, two));
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(c1, PSTrickCardOfPlayer(trick, one));
    XCTAssertEqualObjects(c2, PSTrickCardOfPlayer(trick, two));
    XCTAssertEqualObjects(c3, PSTrickCardOfPlayer(trick, three));
}

// PSTrickRemoveLastCard

-(void)testTrickRemoveLastCard {
    PSPlayer *one = [[PSPlayer alloc] initWithId:0];
    PSPlayer *two = [[PSPlayer alloc] initWithId:1];
    PSPlayer *three = [[PSPlayer alloc] initWithId:2];
    PSTrickHash trick = 0;
    PSCard *c1 = [PSCard cardWithSuit:kSuitClubs andRank:kRankQueen];
    PSCard *c2 = [PSCard cardWithSuit:kSuitClubs andRank:kRankKing];
    PSCard *c3 = [PSCard cardWithSuit:kSuitClubs andRank:kRankAce];
    trick = PSTrickAddCardPlayer(trick, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(c1, PSTrickCardOfPlayer(trick, one));
    XCTAssertEqualObjects(c2, PSTrickCardOfPlayer(trick, two));
    XCTAssertEqualObjects(c3, PSTrickCardOfPlayer(trick, three));
    trick = PSTrickRemoveLastCard(trick);
    XCTAssertEqualObjects(c1, PSTrickCardOfPlayer(trick, one));
    XCTAssertEqualObjects(c2, PSTrickCardOfPlayer(trick, two));
    XCTAssertNil(PSTrickCardOfPlayer(trick, three));
    trick = PSTrickRemoveLastCard(trick);
    XCTAssertEqualObjects(c1, PSTrickCardOfPlayer(trick, one));
    XCTAssertNil(PSTrickCardOfPlayer(trick, two));
    XCTAssertNil(PSTrickCardOfPlayer(trick, three));
    trick = PSTrickRemoveLastCard(trick);
    XCTAssertNil(PSTrickCardOfPlayer(trick, one));
    XCTAssertNil(PSTrickCardOfPlayer(trick, two));
    XCTAssertNil(PSTrickCardOfPlayer(trick, three));
}

// PSTrickTalonCard

-(void)testTrickGetTalonCard {
    PSTrickHash trick = 0;
    PSCard *card = [PSCard cardWithSuit:kSuitClubs andRank:kRankQueen];
    trick = PSTrickAddCardTalon(trick, card.compressed);
    PSCard *back = PSTrickTalonCard(trick);
    XCTAssertEqualObjects(card, back);
}

// PSTrickCard

-(void)testTrickGetPlayerCard {
    PSTrickHash trick = 0;
    PSCard *c1 = [PSCard cardWithSuit:kSuitClubs andRank:kRankQueen];
    PSCard *c2 = [PSCard cardWithSuit:kSuitClubs andRank:kRankKing];
    PSCard *c3 = [PSCard cardWithSuit:kSuitClubs andRank:kRankAce];
    trick = PSTrickAddCardPlayer(trick, 2, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 0, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c3.compressed);
    // Card index follows the order of addition, not player ID
    XCTAssertEqualObjects(c1, PSTrickCard(trick, 0));
    XCTAssertEqualObjects(c2, PSTrickCard(trick, 1));
    XCTAssertEqualObjects(c3, PSTrickCard(trick, 2));
}

// PSTrickCardOwner

-(void)testTrickGetCardOwner {
    PSTrickHash trick = 0;
    PSCard *c1 = [PSCard cardWithSuit:kSuitClubs andRank:kRankQueen];
    PSCard *c2 = [PSCard cardWithSuit:kSuitClubs andRank:kRankKing];
    PSCard *c3 = [PSCard cardWithSuit:kSuitClubs andRank:kRankAce];
    trick = PSTrickAddCardPlayer(trick, 2, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 0, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c3.compressed);
    XCTAssertEqual(2, PSTrickCardOwner(trick, 0));
    XCTAssertEqual(0, PSTrickCardOwner(trick, 1));
    XCTAssertEqual(1, PSTrickCardOwner(trick, 2));
}

// PSTrickCardOfPlayer

-(void)testTrickGetCardOfPlayer {
    PSPlayer *one = [[PSPlayer alloc] initWithId:0];
    PSPlayer *two = [[PSPlayer alloc] initWithId:1];
    PSPlayer *three = [[PSPlayer alloc] initWithId:2];
    PSTrickHash trick = 0;
    PSCard *c1 = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankAce];
    PSCard *c2 = [PSCard cardWithSuit:kSuitHearts andRank:kRankAce];
    PSCard *c3 = [PSCard cardWithSuit:kSuitSpades andRank:kRankAce];
    trick = PSTrickAddCardPlayer(trick, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(c1, PSTrickCardOfPlayer(trick, one));
    XCTAssertEqualObjects(c2, PSTrickCardOfPlayer(trick, two));
    XCTAssertEqualObjects(c3, PSTrickCardOfPlayer(trick, three));
}

// PSTrickCardSuit

-(void)testTrickGetSuitEmpty {
    XCTAssertEqual(PSTrickCardSuit(0), kSuitNone);
}

-(void)testTrickGetSuitWithTalonOnly {
    for (int i = 0 ; i != PS_CARD_SUIT_RISING_LEN ; i++) {
        PSCardSuit suit = PSCardSuitRising[i];
        PSCard *card = [PSCard cardWithSuit:suit andRank:kRankAce];
        PSTrickHash trick = PSTrickAddCardTalon(0, card.compressed);
        XCTAssertEqual(suit, PSTrickCardSuit(trick));
    }
}

-(void)testTrickGetSuitWithTalonAndOtherCards {
    PSCard *c1 = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitHearts andRank:kRankSeven];
    PSCard *c3 = [PSCard cardWithSuit:kSuitSpades andRank:kRankSeven];
    for (int i = 0 ; i != PS_CARD_SUIT_RISING_LEN ; i++) {
        PSCardSuit suit = PSCardSuitRising[i];
        PSCard *card = [PSCard cardWithSuit:suit andRank:kRankAce];
        PSTrickHash trick = PSTrickAddCardTalon(0, card.compressed);
        trick = PSTrickAddCardPlayer(trick, 0, c1.compressed);
        trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
        trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
        XCTAssertEqual(suit, PSTrickCardSuit(trick));
    }
}

-(void)testTrickGetSuitNoTalonSameSuit {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitSpades andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitSpades andRank:kRankNine];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqual(kSuitSpades, PSTrickCardSuit(trick));
}

-(void)testTrickGetSuitNoTalonDifferentSuit {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitHearts andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankNine];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqual(kSuitSpades, PSTrickCardSuit(trick));
}

// PSTrickHighestCard

-(void)testTrickGetHighestSameSuitNoTrump {
    PSCard *c1 = [PSCard cardWithSuit:kSuitHearts andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitHearts andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankNine];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(c3, PSTrickHighestCard(trick, kSuitNone));
}

-(void)testTrickGetHighestMixedSuitNoTrump {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitHearts andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankNine];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(c1, PSTrickHighestCard(trick, kSuitNone));
}

-(void)testTrickGetHighestSameSuitWithMatchingTrump {
    PSCard *c1 = [PSCard cardWithSuit:kSuitHearts andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitHearts andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankNine];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(c3, PSTrickHighestCard(trick, kSuitHearts));
}

-(void)testTrickGetHighestMixedSuitWithMatchingTrump {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankNine];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(c2, PSTrickHighestCard(trick, kSuitDiamonds));
}

-(void)testTrickGetHighestSameSuitWithNonMatchingTrump {
    PSCard *c1 = [PSCard cardWithSuit:kSuitHearts andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitHearts andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankNine];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(c3, PSTrickHighestCard(trick, kSuitSpades));
}

-(void)testTrickGetHighestMixedSuitWithNonMatchingTrump {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankNine];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(c1, PSTrickHighestCard(trick, kSuitClubs));
}

// PSTrickWinner

-(void)testTrickGetWinnerNoTrumpSameSuit {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankJack];
    PSCard *c2 = [PSCard cardWithSuit:kSuitSpades andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitSpades andRank:kRankQueen];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqual(2, PSTrickWinner(trick, kSuitNone));
}

-(void)testTrickGetWinnerNoTrumpDifferentSuit {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankSeven];
    PSCard *c2 = [PSCard cardWithSuit:kSuitHearts andRank:kRankKing];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankAce];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqual(0, PSTrickWinner(trick, kSuitNone));
}

-(void)testTrickGetWinnerWithTrumpSameSuitMatchingTrump {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankJack];
    PSCard *c2 = [PSCard cardWithSuit:kSuitSpades andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitSpades andRank:kRankQueen];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqual(2, PSTrickWinner(trick, kSuitSpades));
}

-(void)testTrickGetWinnerWithTrumpSameSuitNotMatchingTrump {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankJack];
    PSCard *c2 = [PSCard cardWithSuit:kSuitSpades andRank:kRankEight];
    PSCard *c3 = [PSCard cardWithSuit:kSuitSpades andRank:kRankQueen];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqual(2, PSTrickWinner(trick, kSuitDiamonds));
}

-(void)testTrickGetWinnerWithTrumpDifferentSuitMatchingTrump {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankKing];
    PSCard *c2 = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankSeven];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankAce];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqual(1, PSTrickWinner(trick, kSuitDiamonds));
}

// PSTrickDescription

-(void)testTrickDescriptionNoTalonIncomplete {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankKing];
    PSCard *c2 = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankSeven];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    XCTAssertEqualObjects(@"0:♠K 1:♦7 -", PSTrickDescription(trick, kSuitDiamonds));
}

-(void)testTrickDescriptionWithTalonIncomplete {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankKing];
    PSCard *c2 = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankSeven];
    PSCard *t = [PSCard cardWithSuit:kSuitSpades andRank:kRankAce];
    PSTrickHash trick = PSTrickAddCardTalon(0, t.compressed);
    trick = PSTrickAddCardPlayer(trick, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    XCTAssertEqualObjects(@"(♠A)0:♠K 1:♦7 -", PSTrickDescription(trick, kSuitDiamonds));
}

-(void)testTrickDescriptionNoTalonComplete {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankKing];
    PSCard *c2 = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankSeven];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankAce];
    PSTrickHash trick = PSTrickAddCardPlayer(0, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(@"0:♠K 1:♦7 2:♥A w=1", PSTrickDescription(trick, kSuitDiamonds));
}

-(void)testTrickDescriptionWithTalonComplete {
    PSCard *c1 = [PSCard cardWithSuit:kSuitSpades andRank:kRankKing];
    PSCard *c2 = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankSeven];
    PSCard *c3 = [PSCard cardWithSuit:kSuitHearts andRank:kRankAce];
    PSCard *t = [PSCard cardWithSuit:kSuitDiamonds andRank:kRankAce];
    PSTrickHash trick = PSTrickAddCardTalon(0, t.compressed);
    trick = PSTrickAddCardPlayer(trick, 0, c1.compressed);
    trick = PSTrickAddCardPlayer(trick, 1, c2.compressed);
    trick = PSTrickAddCardPlayer(trick, 2, c3.compressed);
    XCTAssertEqualObjects(@"(♦A)0:♠K 1:♦7 2:♥A w=1", PSTrickDescription(trick, kSuitDiamonds));
}

@end
